package com.example.gulimall.search.thread;

import org.apache.tomcat.util.threads.ThreadPoolExecutor;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 线程测试
 * @author GuLin
 * @date 2021-06-25 16:24
 */
public class ThreadTest {

   //线程池
   public static  ExecutorService service = Executors.newFixedThreadPool(10);

    /**
      1.初始化线程的4中方法
         1.1继承Thread
         1.2实现Runnable接口
         1.3实现Callable接口 + FutureTask （可以拿到返回结果，可以处理异常）
         1.4线程池,可以使用以下两种方式操作
             ==>Executors.newFiexedThreadPool(3);
             ==>new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit unit, workQueue, threadFactory, handler);
        总结: 方式1.1、1.2主线程无法获取线程的运算结果，方式1.3可以获取线程中的运算结果，但是不利于控制服务器中的线程资源，容易导致服务器资源耗尽
             方式1.4通过线程性能稳定，也可以获取执行结果，并捕获到异常，但是在业务复杂的情况下一个异步调用可能会依赖另一个异步调用的执行结果
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main....start");
//        两任务组合 - 一个完成
//        当两个任务中，任意一个future任务完成的时候，执行任务。
//        applyToEither：两个任务有一个执行完成，获取它的返回值，处理任务并有新的返回值。
//        acceptEither：两个任务有一个执行完成，获取它的返回值，处理任务，没有新的返回值。
//        runAfterEither：两个任务有一个执行完成，不需要获取future的结果，处理任务，也没有返回值。

        List<CompletableFuture> futures = Arrays.asList(CompletableFuture.completedFuture("hello"),
                CompletableFuture.completedFuture(" world!"),
                CompletableFuture.completedFuture(" hello"),
                CompletableFuture.completedFuture("java!"));
        final CompletableFuture<Void> allCompleted = CompletableFuture.allOf(futures.toArray(new CompletableFuture[]{}));
        allCompleted.thenRun(() -> {
            futures.stream().forEach(future -> {
                try {
                    System.out.println("get future at:"+System.currentTimeMillis()+", result:"+future.get());
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            });
        });


//        两个任务必须都完成，触发该任务。
//        thenCombine：组合两个future，获取两个future的返回结果，并返回当前任务的返回值
//        thenAcceptBoth：组合两个future，获取两个future任务的返回结果，然后处理任务，没有返回值。
//        runAfterBoth：组合两个future，不需要获取future的结果，只需两个future处理完任务后，处理该任务。
//        CompletableFuture.supplyAsync(() -> {
//            return "hello";
//        }).thenApplyAsync(t -> {
//            return t + " world!";
//        }).thenCombineAsync(CompletableFuture.completedFuture(" CompletableFuture"), (t, u) -> {
//            return t + u;
//        }).whenComplete((t, u) -> {
//            System.out.println(t);
//        });



//        handle 是执行任务完成时对结果的处理。
//        handle 是在任务完成后再执行，还可以处理异常的任务。
//        thenApply 方法：当一个线程依赖另一个线程时，获取上一个任务返回的结果，并返回当前任务的返回值。
//        thenAccept方法：消费处理结果。接收任务的处理结果，并消费处理，无返回结果。
//        thenRun方法：只要上面的任务执行完成，就开始执行thenRun，只是处理完任务后，执行 thenRun的后续操作
//        带有Async默认是异步执行的。这里所谓的异步指的是不在当前线程内执行。
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {
//            @Override
//            public Integer get() {
//                System.out.println(Thread.currentThread().getName() + "\t completableFuture");
//                int i = 10 / 0;
//                return i;
//            }
//        }).thenApply(new Function<Integer, Integer>() {
//            @Override
//            public Integer apply(Integer integer) {
//                System.out.println("thenApply方法，上次返回结果：" + integer);
//                return integer * 2;
//            }
//        }).whenComplete(new BiConsumer<Integer, Throwable>() {
//            @Override
//            public void accept(Integer integer, Throwable throwable) {
//                System.out.println("-------integer=" + integer);
//                System.out.println("-------throwable=" + throwable);
//            }
//        }).exceptionally(new Function<Throwable, Integer>() {
//            @Override
//            public Integer apply(Throwable throwable) {
//                System.out.println("throwable=" + throwable);
//                return 6666;
//            }
//        }).handle(new BiFunction<Integer, Throwable, Integer>() {
//            @Override
//            public Integer apply(Integer integer, Throwable throwable) {
//                System.out.println("handle integer=" + integer);
//                System.out.println("handle throwable=" + throwable);
//                return 8888;
//            }
//        });
//        System.out.println(future.get());


//        whenComplete 和 whenCompleteAsync 的区别：
//        whenComplete：是执行当前任务的线程执行继续执行 whenComplete 的任务。
//        whenCompleteAsync：是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行。
//        CompletableFuture future = CompletableFuture.supplyAsync(new Supplier<Object>() {
//            @Override
//            public Object get() {
//                System.out.println(Thread.currentThread().getName() + "\t completableFuture");
//                int i = 10 / 0;
//                return 1024;
//            }
//        }).whenComplete(new BiConsumer<Object, Throwable>() {
//            @Override
//            public void accept(Object o, Throwable throwable) {
//                System.out.println("-------o=" + o.toString());
//                System.out.println("-------throwable=" + throwable);
//            }
//        }).exceptionally(new Function<Throwable, Object>() {
//            @Override
//            public Object apply(Throwable throwable) {
//                System.out.println("throwable=" + throwable);
//                return 6666;
//            }
//        });
//        System.out.println(future.get());



        //supplyAsync可以支持返回值。
//        CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程id===>" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("处理结果===>" + i);
//            return  i;
//        }, service);
//        System.out.println(supplyAsync.get());

          //runAsync方法不支持返回值。
//        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
//            System.out.println("当前线程id===>" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("处理结果===>" + i);
//        }, service);

        //1.4线程池,可以使用以下两种方式操作
//        service.execute(new Runnable01());
//        Future<Integer> submit = service.submit(new Callable01());
//        System.out.println(submit);

        //1.3实现Callable接口 + FutureTask （可以拿到返回结果，可以处理异常）
//        main....start
//        当前线程id===>1
//        处理结果===>5
//        获取回调函数结果===>5
//        main...end
//        Callable01 callable01 = new Callable01();
//        try {
//            Integer call = callable01.call();
//            System.out.println("获取回调函数结果===>"+call);
//        } catch (Exception e) {
//            System.out.println(e.getMessage());
//        }

        // 1.2实现Runnable接口
//        main....start
//        当前线程id===>1
//        处理结果===>5
//        main...end
//        Runnable01 runnable01 = new Runnable01();
//        runnable01.run();

        //1.1继承Thread线程
//        main....start
//        main...end
//        当前线程id===>12
//        处理结果===>5
//        Thread01 thread01 = new Thread01();
//        thread01.start();


        System.out.println("main...end");
    }

    private static void threadPool(){
        ExecutorService threadPool = new ThreadPoolExecutor(
                200,
                10,
                10L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<Runnable>(10000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        //定时任务的线程池
        ExecutorService service = Executors.newScheduledThreadPool(2);
    }

    public static class Callable01 implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            System.out.println("Callable01当前线程id===>"+Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("处理结果===>"+i);
            return i;
        }
    }

    public static class Runnable01 implements Runnable{
        @Override
        public void run() {
            System.out.println("Runnable01当前线程id===>"+Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("处理结果===>"+i);
        }
    }

    public static  class Thread01 extends Thread{
        @Override
        public void run() {
            System.out.println("Thread01当前线程id===>"+Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("处理结果===>"+i);
        }
    }
}
